<template>
  <div class="element-table-root">
    <slot name="toolbar" v-if="$slots.toolbar"></slot>
    <div v-else class="element-table-toolbar">
      <el-form :inline="true" class="demo-form-inline">

        <el-row :gutter="10">
          <template v-for="(columnItem, index) in columns" :key="index">
            <el-col :span="rowSpan" v-if="columnItem.select" class="row-col">
              <div class="toolbar">
                <div class="toolbar-item toolbar-select"
                     v-if="columnItem.formatter&&(columnItem.formatter.type=='dict'||columnItem.formatter.type=='dictTag')">
                  <FormDictSelect :label="columnItem.title" v-model:value="searchParams[columnItem.field]"
                                  :dictType="columnItem.formatter.dictType"/>

                </div>
                <div class="toolbar-item toolbar-select"
                     v-else-if="columnItem.formatter&&columnItem.formatter.type=='org'">
                  <FormOrgSelect :label="columnItem.title" v-model:value="searchParams[columnItem.field]"/>

                </div>
                <div class="toolbar-item toolbar-select"
                     v-else-if="columnItem.formatter&&columnItem.formatter.type=='region'">
                  <FormRegionSelect :label="columnItem.title" v-model:value="searchParams[columnItem.field]"/>
                </div>
                <div class="toolbar-item toolbar-select"
                     v-else-if="columnItem.formatter&&columnItem.formatter.type=='date'">
                  <FormDatePicker :label="columnItem.title"
                                  v-model:value="searchParams[columnItem.field]"
                                  :type="columnItem.formatter.dateType"
                                  :defaultValue="columnItem.formatter.defaultValue"
                                  :rangeHour="columnItem.formatter.rangeHour"
                                  :defaultType="columnItem.formatter.defaultType"
                                  :defaultHour="columnItem.formatter.defaultHour"
                                  :format="columnItem.formatter.dateFormat?columnItem.formatter.dateFormat:'YYYY-MM-DD'"
                  />
                </div>
                <div v-else-if="columnItem.formatter&&columnItem.formatter.type=='inputNumber'"
                     class="toolbar-item toolbar-select">
                  <FormInputNumber :label="columnItem.title" v-model:value="searchParams[columnItem.field]"
                                   :min="columnItem.formatter.min"
                                   :defaultValue="columnItem.formatter.defaultValue"
                                   :unit="columnItem.formatter.unit"
                                   :max="columnItem.formatter.max" :step="columnItem.formatter.step"/>
                </div>
                <div v-else class="toolbar-item toolbar-select">
                  <el-input v-model="searchParams[columnItem.field]" size="default">
                    <template #prepend>{{ columnItem.title }}</template>
                  </el-input>
                </div>

              </div>
            </el-col>
          </template>
          <el-col :span="rowSpan" class="row-col " v-if="showCell">
            <CellSelectShow :tableColumns="tableColumns" label="列名展示"></CellSelectShow>
          </el-col>
          <el-col :span="rowSpan" :push="(pushSpan)" class="row-col col-opt">
            <div style="float:right">
              <el-button type="primary" plain icon="Search"
                         v-if="searchBtnShow"
                         @click="reloadTable({...params,...searchParams})">
                查询
              </el-button>
              <el-button type="danger" plain icon="Share" @click="resetData"
                         v-if="resetBtnShow"
              >重置
              </el-button>
              <el-button type="primary" plain icon="Plus" v-if="addBtnShow" @click="tableEvent('add',{})">新增
              </el-button>
              <slot name="toolbarBtn" v-if="$slots.toolbarBtn" :params="{...params,...searchParams}"></slot>
            </div>
          </el-col>
        </el-row>

      </el-form>

    </div>
    <el-table
        ref="rootTable"
        border
        key="myTable"
        :height="height"
        v-model:data="tableData"
        highlight-current-row
        v-loading="loading"
        :stripe="stripe"
        element-loading-text="数据加载中..."
        :element-loading-spinner="svg"
        element-loading-svg-view-box="-10, -10, 50, 50"
        element-loading-background="rgba(122, 122, 122, 0.8)"
        @select="checkboxEvent"
        @select-All="checkboxAllEvent"
        style="width: 100%;">
      >
      <template v-for="(item,index) in tableColumns"
                :key="index">
        <el-table-column v-if="item.type" :type="item.type"></el-table-column>

        <el-table-column
            v-else-if="item.showCell==undefined || item.showCell==true "
            :prop="item.formatter?(item.formatter.type?((item.formatter.type=='dict'||item.formatter.type=='org'||item.formatter.type=='region'||item.formatter.type=='other'||item.formatter.type=='dictTag')?item.field+'Label':item.field):item.field):item.field"
            :fixed="item.fixed"
            :label="item.title"
            :header-align="item.headerAlign"
            :align="item.align"
            :width="item.width">
          <template #default="scope" v-if="item.formatter">
            <slot :name="item.field" v-if="item.formatter.type=='opt'&&$slots[item.field]"
                  :row="scope.row"
                  :rowIndex="scope.$index"
            ></slot>
            <div v-else-if="item.formatter.type=='opt'">
              <el-tooltip content="编辑" placement="bottom" v-if="editBtnShow">
                <el-button type="primary" icon="Edit" size="small" @click="tableEvent('edit',scope.row)" circle/>
              </el-tooltip>
              <el-tooltip content="删除" placement="bottom" v-if="deleteBtnShow">
                <el-button type="danger" icon="Delete" size="small" circle @click="tableEvent('delete',scope.row)"/>
              </el-tooltip>
              <el-tooltip content="查看" placement="bottom">
                <el-button type="primary" plain icon="Document" size="small" circle
                           @click="tableEvent('view',scope.row)"/>
              </el-tooltip>
            </div>
            <el-tag v-else-if="item.formatter.type=='tag'"
                    :type="selectTag(scope.row[item.field],item.formatter.tagType)"
                    disable-transitions>
              {{ scope.row[item.field] }}
            </el-tag>
            <DictLabelTag v-else-if="item.formatter.type=='dictTag'"
                          :value="scope.row[item.field]"
                          :dictType="item.formatter.dictType"
                          :tagType="item.formatter.tagType"
            ></DictLabelTag>
            <div v-else-if="item.editor">
              <el-input size="small" :model-value="scope.row[item.field]"
                        @input="value => tableInputChange(value, scope.row,item.field,item.editor)"/>

            </div>
            <span v-else v-html="RenderCell(scope.row,item)"></span>
          </template>
        </el-table-column>
      </template>


    </el-table>
    <div style="width:100%;height:24px;padding:10px 0px;" v-if="!hidePage">
      <div v-if="pageText" style="width:400px;float:left;line-height: 24px;font-size: 12px;color:red"
           v-html="pageText"></div>
      <el-pagination
          small
          background
          v-if="!hidePage"
          layout="total,prev, pager, next"
          style="margin:10px 0px;float:right"
          v-model:current-page="page.pageNo"
          v-model:page-size="page.pageSize"
          @current-change="handleCurrentChange"
          :total="pageTotal"
          class="mt-4"
      />
    </div>

  </div>
</template>

<script lang="ts" setup>
//定义组件名称
// @ts-ignore
import {ElMessage} from "element-plus/es";

defineOptions({
  name: "PageTable"
});
// @ts-ignore
import {ref, onMounted, getCurrentInstance, watch} from 'vue'

/**
 * 接收的参数
 * coloumn:[
 * {
 *  title: '操作',
 *  showCell:true,是否展示列
 *  dynamicCell:true,动态展示列
 *     field: 'opt',
 *     width: 150,
 *     align: 'center',
 *     headerAlign: 'center',
 *     formatter: {
 *       type: 'opt'     suport : opt ,org,region,dict,tag, other,date,dictTag
 *       dateType:'monthrange',日期的类型支持date,daterange,month,monthrange,week,weekrange等
 *       dateFormat:'YYYYMM',日期格式
 *       defaultValue: true,
 *       defaultType:'date'
 *       action:''      other 时的 uri 地址;接收 id 参数
 *       name:''         other 时的 uri 返回的对象反射字段
 *       dictType:'sex'  in type is dict and dictTag is used,
 *       tagType:[       in type is tag is used
 *       {
 *        gt: 大于
 *        lt: 小于
 *        gte: 大于等于
 *        lte: 小于等于
 *        eq: 等于
 *       },
 *       type:''
 *       ]
 *     }
 * }
 * ],
 * actiion :数据请求的地址
 * hidePage: 是否隐藏分页
 */
const props = defineProps({
  action: {type: String, required: false},
  columns: {type: Array, required: true},
  height: {type: Number, required: true},
  hidePage: {type: Boolean, required: true},
  addBtnShow: {type: Boolean, required: true, default: true},
  resetBtnShow: {type: Boolean, required: true, default: true},
  searchBtnShow: {type: Boolean, required: true, default: true},
  editBtnShow: {type: Boolean, required: true, default: true},
  deleteBtnShow: {type: Boolean, required: true, default: true},
  params: {type: Object, required: false},
  showCell: {type: Boolean, required: false},
  stripe: {type: Boolean, required: false, default: false},
  pageSize: {type: Number, required: false, default: 10},
  // 提示
  pageText: {type: String, required: false, default: ''},
  //自动加载
  autoLoadData: {type: Boolean, required: true, default: true},
  //滚动到底部自动加载
  bottomLoadData: {type: Boolean, required: true, default: false},
});

//默认table组件
const rootTable = ref<any>();
//加载load...
let loading = ref(false);

//表格数据
let tableData: any = ref<any>([]);

//row-col :span
let rowSpan = ref(6);
//opt-col :push
let pushSpan = ref(0);

const tableColumns = ref<any>(props.columns);

//opt-col :push
let pushEvent = () => {
  let cellIndex = 0;
  let searchColumn = 0;
  for (let i = 0; i < props.columns.length; i++) {
    let col: any = props.columns[i];
    if (col.select) {
      searchColumn = searchColumn + 1;
    }
  }
  //总span
  let totalSpan = searchColumn * rowSpan.value;
  //预多少
  let rowNum = totalSpan % 24;
  if (props.showCell) {
    cellIndex = rowSpan.value;
  }
  pushSpan.value = (24 - (rowNum + rowSpan.value + cellIndex));
}

// @ts-ignore
let {proxy} = getCurrentInstance()

let pageTotal = ref(0);

let page = ref({pageNo: 1, pageSize: props.pageSize});


//查询条件
let searchParams = ref<any>({});

// @ts-ignore
let dictMap = new Map();

let orgMap = new Map();

let regionMap = new Map();

let otherMap = new Map();
//监听变化
watch(() => props.params, () => {
  searchParams.value = {...props.params, ...searchParams.value}
  reloadTable(searchParams.value);
})
const svg = ` <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>`;
let scrollDom: any = null;

onMounted(() => {
  pushEvent();
  setTimeout(function () {
    if (props.autoLoadData) {
      reloadTable(searchParams.value)
    }
  }, 100)
  if (props.bottomLoadData && props.hidePage) {
    scrollDom = rootTable.value.$refs.bodyWrapper;
    console.log(rootTable.value, scrollDom);
    scrollDom.addEventListener("mousewheel", scrollBehavior);
  }
});
const emit = defineEmits(['update:resetParams'])

/**
 * 加载数据
 */
let reloadTable = (searchParams: any) => {
  loading.value = true;
  let pageInfo: any = Object.assign({
    pageNo: page.value.pageNo,
    pageSize: page.value.pageSize
  }, props.params, searchParams);
  proxy.$http.post(props.action, pageInfo).then((res: any) => {
    loading.value = false;
    if (props.bottomLoadData) {
      if (tableData.value.length > 0) {
        tableData.value = tableData.value.concat(res.data.rows)
      } else {
        tableData.value = res.data.rows;
      }
    } else {
      tableData.value = res.data.rows;
    }
    pageTotal.value = res.data.total;
  });
}

let selectTag = (value: any, tagList: any) => {
  let tagType = '';
  for (let i = 0; i < tagList.length; i++) {
    let tag = tagList[i];
    if (tag.eq && value == tag.eq) {
      tagType = tag.type;
    } else if (tag.gt && value > tag.gt) {
      if (tag.lt && value < tag.lt) {
        tagType = tag.type;
      } else if (tag.lte && value <= tag.lte) {
        tagType = tag.type;
      } else {
        tagType = tag.type;
      }
    } else if (tag.gte && value >= tag.gte) {
      if (tag.lt && value < tag.lt) {
        tagType = tag.type;
      } else if (tag.lte && value <= tag.lte) {
        tagType = tag.type;
      } else {
        tagType = tag.type;
      }
    }
  }
  return tagType;
}

/**
 * 渲染tableColumn
 * @param v
 */
let RenderCell = (row: any, item: any) => {
  let id = row[item.field]
  let keyName = item.field + "_" + id;
  if (item.formatter && item.formatter.type == 'org') {
    if (orgMap.get(keyName) === null || orgMap.get(keyName) === undefined) {
      new Promise((resolve, reject) => {
        if (id && typeof id === 'number') {
          proxy.$http.tablePost("/user-center/org/findOne", {id: id}).then((res: any) => {
            resolve(res.data);
          });
        }
      }).then((res: any) => {
        if (res.code == 0 && res.data) {
          row[item.field + 'Label'] = res.data.orgName
          orgMap.set(keyName, res.data.orgName)
        } else if (id == -1) {
          row[item.field + 'Label'] = "顶级机构"
        }
      })
    } else {
      row[item.field + 'Label'] = orgMap.get(keyName);
    }

  } else if (item.formatter && item.formatter.type == 'dict') {
    if (!dictMap.get(keyName)) {
      new Promise((resolve, reject) => {
        proxy.$http.tablePost("/user-center/dict/findLabel", {
          value: row[item.field],
          dictType: item.formatter.dictType
        }).then((res: any) => {
          resolve(res.data);
        });
      }).then((res: any) => {
        if (res.code == 0 && res.data) {
          row[item.field + 'Label'] = res.data.label;
          dictMap.set(keyName, res.data.label);
        }
      })
    } else {
      row[item.field + 'Label'] = dictMap.get(keyName);
    }
  } else if (item.formatter && item.formatter.type == 'region') {
    if (!regionMap.get(keyName)) {
      new Promise((resolve, reject) => {
        if (id && typeof id === 'number') {
          proxy.$http.tablePost("/user-center/region/findOne", {'id': id}).then((res: any) => {
            resolve(res.data);
          });
        }
      }).then((res: any) => {
        if (res.code == 0 && res.data) {
          row[item.field + 'Label'] = res.data.regionName
          regionMap.set(keyName, res.data.regionName);
        }
      })
    } else {
      row[item.field + 'Label'] = regionMap.get(keyName);
    }

  } else if (item.formatter && item.formatter.type == 'other') {
    if (!otherMap.get(keyName)) {
      new Promise((resolve, reject) => {
        if (id && typeof id === 'number') {
          proxy.$http.tablePost(item.formatter.action, {'id': id}).then((res: any) => {
            resolve(res.data);
          });
        }
      }).then((res: any) => {
        if (res.code == 0 && res.data) {
          row[item.field + 'Label'] = res.data[item.formatter.name]
          otherMap.set(keyName, res.data[item.formatter.name])
        }
      })
    } else {
      row[item.field + 'Label'] = otherMap.get(keyName)
    }
  }
  if (row[item.field + 'Label']) {
    return row[item.field + 'Label'];
  } else {
    return row[item.field];
  }
}

function handleCurrentChange(page: number) {
  reloadTable(searchParams.value)
}

function resetData() {
  searchParams.value = {};
  setTimeout(function () {
    reloadTable({
      ...props.params,
      ...searchParams.value
    });
  }, 100)
}

//打开 dialog 窗口
const tableEvent = (type: string, row: any) => {
  proxy.$parent.$parent.optColumnEvent(type, row);
}
const deleteTable = (action: string, rowId: any) => {
  proxy.$http.post(action, {
    id: rowId
  }).then(function (api: any) {
    if (api.code == 0) {
      ElMessage({
        message: '删除成功',
        type: 'success',
      })
      reloadTable({
        ...searchParams.value,
        ...props.params
      });
    } else if (api.msg) {
      ElMessage({
        message: api.msg,
        type: 'error',
      })
    } else {
      ElMessage({
        message: '删除失败',
        type: 'error',
      })
    }
  }).catch(function () {
    ElMessage({
      message: '操作失败',
      type: 'error',
    })
  });
}

/**
 * table 可编辑列
 * @param value
 * @param row
 */
const tableInputChange = (value: any, row: any, field: string, editor: any) => {
  row[field] = value;
  if (editor.saveUri) {
    proxy.$http.post(editor.saveUri, row).then((apiData: any) => {
      console.log("编辑列成功:", apiData);
    })
  } else {
    ElMessage.error("editor的saveUri属性不能为空");
  }
}
//checkBoxValue 值
let checkBoxValue: any = [];
//选择checkbox
const checkboxEvent = (selection: any, row: any) => {
  checkBoxValue = selection;
}
//选择全部checkbox
const checkboxAllEvent = (selection: any) => {
  checkBoxValue = selection;
}

//返回选择的数组
const getCheckBoxValue = () => {
  return checkBoxValue;
}

function scrollBehavior(e: any) {
  // 滚动方向判定
  const scrollDirection = e.deltaY > 0 ? 'down' : 'up'
  if (scrollDirection === 'down') {
    // 获取提供实际滚动的容器
    const dom = rootTable.value.$refs.bodyWrapper.getElementsByClassName('el-scrollbar__wrap')[0]

    const {clientHeight, scrollTop, scrollHeight} = dom;
    console.log(clientHeight,scrollTop,scrollHeight,parseInt((clientHeight + scrollTop + 1).toFixed(0)));

    // 父容器高度 + 子容器距离父容器顶端的高度 = 子容器可滚动的高度
    if ((clientHeight + scrollTop + 1).toFixed(0) >= scrollHeight) {
      if (!loading.value) {
        page.value.pageNo = page.value.pageNo + 1;
        reloadTable({
          ...searchParams.value,
          ...props.params
        })
      }

    }
  }
}

defineExpose({
  reloadTable, deleteTable, getCheckBoxValue
});
</script>
